Go语言:validator库对请求参数校验

您所在的位置:网站首页 switch 翻译器 Go语言:validator库对请求参数校验

Go语言:validator库对请求参数校验

2023-07-18 20:49| 来源: 网络整理| 查看: 265

validator库参数校验 1.介绍

validator 库做参数校验是否实用,包括错误翻译等提示

下载

go get github.com/go-playground/validator/v10 2.gin内置校验 先看一下gin内置validator做校验 package main import ( "github.com/gin-gonic/gin" "net/http" ) type SignUpParam struct { Age uint8 `json:"age" binding:"gte=1,lte=130"` Name string `json:"name" binding:"required"` Email string `json:"email" binding:"required,email"` Password string `json:"password" binding:"required"` RePassword string `json:"re_password" binding:"required,eqfield=Password"` } func main() { r := gin.Default() r.POST("/signup", func(c *gin.Context) { var u SignUpParam if err := c.ShouldBind(&u);err!=nil{ c.JSON(http.StatusOK, gin.H{ "msg":err.Error(), }) return } // 执行逻辑,保存db c.JSON(http.StatusOK,"success") }) _ = r.Run(":28282") } 我们用postman 发送请求 { "age":28, "name":"liSir", "email":"[email protected]" } // 会返回来错误信息 { "msg": "Key: 'SignUpParam.Password' Error:Field validation for 'Password' failed on the 'required' tag\nKey: 'SignUpParam.RePassword' Error:Field validation for 'RePassword' failed on the 'required' tag" } // 可以看到validator检验不通过。但都是英文。 3.如何将校验错误信息翻译成中文 validator库支持国际化,借助相应语言包可以实现校验错误提示信息自动翻译。 package main import ( "fmt" "github.com/gin-gonic/gin" "github.com/gin-gonic/gin/binding" "github.com/go-playground/locales/en" "github.com/go-playground/locales/zh" ut "github.com/go-playground/universal-translator" "github.com/go-playground/validator/v10" enTranslations "github.com/go-playground/validator/v10/translations/en" zhTranslations "github.com/go-playground/validator/v10/translations/zh" "net/http" ) type SignUpParam struct { Age uint8 `json:"age" binding:"gte=1,lte=130"` Name string `json:"name" binding:"required"` Email string `json:"email" binding:"required,email"` Password string `json:"password" binding:"required"` RePassword string `json:"re_password" binding:"required,eqfield=Password"` } // 全局翻译器T var trans ut.Translator func InitTrans(locale string) (err error){ //修改gin框架中Validator引擎属性,实现自定制 if v,ok := binding.Validator.Engine().(*validator.Validate);ok{ zhT := zh.New()//中文翻译器 enT := en.New()//英文翻译器 // 第一个参数是备用(fallback)语言环境 // 后面参数是应该支持语言环境(可支持多个) uni := ut.New(enT,zhT,enT) // locale通常取决于http请求'Accept-language' var ok bool trans,ok = uni.GetTranslator(locale) if !ok{ return fmt.Errorf("uni.GetTranslator(%s) failed", locale) } // 注册翻译器 switch locale{ case "en": err = enTranslations.RegisterDefaultTranslations(v, trans) case "zh": err = zhTranslations.RegisterDefaultTranslations(v, trans) default: err = enTranslations.RegisterDefaultTranslations(v, trans) } return } return } func main() { // 注册中文翻译器 if err:= InitTrans("zh");err != nil{ fmt.Printf("init trans failed,err %v\n",err) return } r := gin.Default() r.POST("/signup", func(c *gin.Context) { var u SignUpParam if err := c.ShouldBind(&u);err!=nil{ //获取validator.ValidationErrors类型的errors errs,ok := err.(validator.ValidationErrors) // 非validator类型错误直接返回 if !ok{ c.JSON(http.StatusOK,gin.H{ "message":err.Error(), }) return } // valodator.ValidationErrors类型错误进行翻译 c.JSON(http.StatusOK,gin.H{ "message":errs.Translate(trans), }) } // 执行逻辑,保存db c.JSON(http.StatusOK,"success") }) _ = r.Run(":28282") } 返回结果 { "message": { "SignUpParam.Password": "Password为必填字段", "SignUpParam.RePassword": "RePassword为必填字段" } }"success" 4.自定义错误提示信息字段名 错误信息提示中的字段用自定义的名称,例如json tag指定的值呢? if v,ok := binding.Validator.Engine().(*validator.Validate);ok{ // 注册一个获取json tag的自定义方法 v.RegisterTagNameFunc(func(fld reflect.StructField) string { name := strings.SplitN(fld.Tag.Get("json"),",",2)[0] if name == "-"{ return "" } return name }) .... 再次发送请求 { "message": { "SignUpParam.password": "password为必填字段", "SignUpParam.re_password": "re_password为必填字段" } }"success" 可以看到错误提示信息使用就是我们结构体中json tag设置的名称。但是前段提示信息不需要提示SignUpParam,这里可以去掉结构体名称前缀, func removeTopStruct(fields map[string]string) map[string]string { res := map[string]string{} for field, err := range fields { res[field[strings.Index(field, ".")+1:]] = err } return res } 我们在代码中使用上述翻译后 if err := c.ShouldBind(&u); err != nil { // 获取validator.ValidationErrors类型的errors errs, ok := err.(validator.ValidationErrors) if !ok { // 非validator.ValidationErrors类型错误直接返回 c.JSON(http.StatusOK, gin.H{ "msg": err.Error(), }) return } // validator.ValidationErrors类型错误则进行翻译 // 并使用removeTopStruct函数去除字段名中的结构体名称标识 c.JSON(http.StatusOK, gin.H{ "msg": removeTopStruct(errs.Translate(trans)), }) } 最终显示效果 { "message": { "password": "password为必填字段", "re_password": "re_password为必填字段" } }"success" 如果我们想将上面Password字段也改为json // SignUpParamStructLevelValidation 自定义SignUpParam结构体校验函数 func SignUpParamStructLevelValidation(sl validator.StructLevel) { su := sl.Current().Interface().(SignUpParam) if su.Password != su.RePassword { // 输出错误提示信息,最后一个参数就是传递的param sl.ReportError(su.RePassword, "re_password", "RePassword", "eqfield", "password") } } 在初始化校验器的函数中注册自定义校验方法即可 func InitTrans(locale string) (err error) { // 修改gin框架中的Validator引擎属性,实现自定制 if v, ok := binding.Validator.Engine().(*validator.Validate); ok { // ... liwenzhou.com ... // 为SignUpParam注册自定义校验方法 v.RegisterStructValidation(SignUpParamStructLevelValidation, SignUpParam{}) zhT := zh.New() // 中文翻译器 enT := en.New() // 英文翻译器 // ... liwenzhou.com ... } 5.自定义校验方法 type SignUpParam struct{ ... Date string `json:"date" binding:"required,datetime=2006-01-02,checkDate" }

其中datetime=2006-01-02是内置的用于校验日期类参数是否满足指定格式要求的tag。 如果传入的date参数不满足2006-01-02这种格式就会提示如下错误:

// customFunc 自定义字段级别校验方法 func customFunc(fl validator.FieldLevel) bool { date, err := time.Parse("2006-01-02", fl.Field().String()) if err != nil { return false } if date.Before(time.Now()) { return false } return true } // 在校验器注册自定义的校验方法 if err := v.RegisterValidation("checkDate", customFunc); err != nil { return err } 6.自定义翻译方法 // registerTranslator 为自定义字段添加翻译功能 func registerTranslator(tag string, msg string) validator.RegisterTranslationsFunc { return func(trans ut.Translator) error { if err := trans.Add(tag, msg, false); err != nil { return err } return nil } } // translate 自定义字段的翻译方法 func translate(trans ut.Translator, fe validator.FieldError) string { msg, err := trans.T(fe.Tag(), fe.Field()) if err != nil { panic(fe.(error).Error()) } return msg } 定义好相关翻译方法,再初始化 func InitTrans(locale string) (err error) { // ...liwenzhou.com... // 注册翻译器 switch locale { case "en": err = enTranslations.RegisterDefaultTranslations(v, trans) case "zh": err = zhTranslations.RegisterDefaultTranslations(v, trans) default: err = enTranslations.RegisterDefaultTranslations(v, trans) } if err != nil { return err } // 注意!因为这里会使用到trans实例 // 所以这一步注册要放到trans初始化的后面 if err := v.RegisterTranslation( "checkDate", trans, registerTranslator("checkDate", "{0}必须要晚于当前日期"), translate, ); err != nil { return err } return } return }


【本文地址】


今日新闻


推荐新闻


CopyRight 2018-2019 办公设备维修网 版权所有 豫ICP备15022753号-3